package club.banyuan.mbm;

import club.banyuan.mbm.util.MbmSession;
import club.banyuan.mbm.util.SessionUtil;
import com.alibaba.fastjson.JSONObject;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.*;

public class HttpServerConcurrent extends Thread {

    private static UserService userService = new UserService();
    private static ProviderService providerService = new ProviderService();
    private static BillService billService = new BillService();

    private final Socket socket;

    public HttpServerConcurrent(Socket socket) {
        this.socket = socket;
    }


    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(5000);

        userService = UserService.load();
        providerService = ProviderService.load();
        billService = BillService.load();

        while (true) {
            System.out.println("等待浏览器");
            Socket socket = serverSocket.accept();
            HttpServerConcurrent serverConcurrent = new HttpServerConcurrent(socket);
            serverConcurrent.start();
        }

    }

    @Override
    public void run() {
        try {
            InputStream inputStream = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

            Request request = Request.parse(reader);
            if (request == null) {
                System.out.println("解析失败");
                return;
            }

            System.out.println("向浏览器写入数据");

            // 头部数据读取完毕后，回复页面文件数据之前，需要按照HTTP的格式要求，回复以下内容
            // 回复内容时，需要有一个状态编码，表示请求的结果
            // 404 资源找不到  /abcd.txt    400 bad request 请求数据异常   500 服务器异常
            // HTTP/1.1 200 OK
            // Content-Type: text/html; charset=utf-8
            // Content-Length: 1234
            //
            OutputStream outputStream = socket.getOutputStream();

            String url = request.getUrl();
            String resourcePath = "/pages";
            if ("/".equals(url)) {
                resourcePath += "/login.html";
                writeStaticResource(outputStream, resourcePath,request);
            } else if (url.startsWith("/css") || url.startsWith("/images") || url.startsWith("/js") || url
                    .endsWith(".html")) {
                resourcePath += url;
                // 如果xxxx.html不存在，统统返回404.html 内容
                // 通过查询资源看是否为null进行判断
                if (resourcePath.endsWith(".html")
                        && HttpServerConcurrent.class.getResource(resourcePath) == null) {
                    resourcePath = "/pages/404.html";
                }

                writeStaticResource(outputStream, resourcePath,request);
            } else if (url.startsWith("/server")) {
                // 以/server开头的路径，都不是请求静态资源的，而是需要处理数据
                processData(outputStream, request);

            } else {
                System.out.println("路径不合法");
                return;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void processData(OutputStream outputStream, Request request) throws IOException {
        String url = request.getUrl();

        validataAuth(url, request);

        switch (url) {
            case "/server/user/login": {
                Map<String, String> formData = request.getFormData();
                User user = new User();
                user.setName(formData.get("name"));
                user.setPwd(formData.get("pwd"));
                User loginUser = userService.userLogin(user);
                // 通过发送http状态码 302(重定向) + 一个新的请求路径，让浏览器收到回复后立即发送一个新的请求到新的路径上
                if (loginUser == null) {
                    // 登录失败， 跳转回login.html
                    setRedirect(outputStream, request, "/login.html");
                    // http://127.0.0.1:5000/login.html
                } else {
                    request.getMbmSession().put("user", loginUser);
                    // 登录成功， 跳转到bill_list.html 页面
                    setRedirect(outputStream, request, "/user_list.html");
                }
            }
            break;
            case "/server/user/list": {
                System.out.println("查询用户列表");
                System.out.println(request.getJsonData());
                List<User> userList;
                if (request.getJsonData() != null) {
                    User user = JSONObject.parseObject(request.getJsonData(), User.class);
                    userList = userService.getUserList(user);
                } else {
                    userList = userService.getUserList();
                }


                sendJsonResponse(outputStream, userList, request);
            }
            break;
            case "/server/user/delete": {
                System.out.println("删除用户");
                System.out.println(request.getJsonData());
                User user = JSONObject.parseObject(request.getJsonData(), User.class);
                userService.deleteUser(user.getId());
                userService.save();

                sendJsonResponse(outputStream, userService.getUserList(), request);
            }
            break;
            case "/server/user/modify": {
                System.out.println("修改用户或添加用户");
                System.out.println(request.getFormData());
                Map<String, String> formData = request.getFormData();
                // 将Map序列化为JSON字符串，然后将json反序列化为User对象
                String s = JSONObject.toJSONString(formData);
                User user = JSONObject.parseObject(s, User.class);

//                User user = new User();
//                user.setId(Integer.parseInt(formData.get("id")));
//                user.setName(formData.get("name"));
//                user.setPwd(formData.get("pwd"));
//                user.setUserType(Integer.parseInt(formData.get("userType")));

                try {
                    if (user.getId() == 0) {
                        userService.addUser(user);
                    } else {
                        userService.updateUser(user);
                    }
                    userService.save();
                    // 操作成功：重定向到user_list.html
                    setRedirect(outputStream, request, "/user_list.html");
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                    sendFailure(outputStream, e.getMessage(), request);
                }


//                if (formData.get("pwd").equals(formData.get("pwdConfirm"))) {
//                    if (userService.getUser(Integer.parseInt(formData.get("id"))) == null) {
//                        // 表示没有这个用户，新添加用户
//                        userService.addUser(user);
//                    } else {
//                        // 表示有这个用户，更新用户
//                        userService.updateUser(user);
//                    }
//                    userService.save();
//                    // 操作成功：重定向到user_list.html
//                    setRedirect(outputStream, request, "/user_list.html");
//                } else {
//                    // 操作失败：重定向到form_post_fail.html
//                    setRedirect(outputStream, request, "/form_post_fail.html");
//                }
            }
            break;

            case "/server/user/get": {
                System.out.println("根据id查询用户");
                System.out.println(request.getJsonData());
                User user = JSONObject.parseObject(request.getJsonData(), User.class);
                User rlt = userService.getUser(user.getId());
                sendJsonResponse(outputStream, rlt, request);
            }
            break;


            // 供应商模块
            // 供应商修改或添加
            case "/server/provider/modify": {
                System.out.println("供应商修改或添加");
                System.out.println(request.getFormData());
                Provider provider = JSONObject.parseObject(JSONObject.toJSONString(request.getFormData()), Provider.class);
                if (provider != null) {
                    if (provider.getId() == 0) {
                        // 表示没有该供应商 就新添加
                        providerService.addProvider(provider);
                    } else {
                        // 表示有该供应商 修改信息
                        providerService.updateProvider(provider);
                    }
                    setRedirect(outputStream, request, "/provider_list.html");
                    providerService.save();
                } else
                    setRedirect(outputStream, request, "/form_post_fail.html");
            }
            break;

            // 查询供应商列表
            case "/server/provider/list": {
                System.out.println("查询供应商列表");
                System.out.println(request.getJsonData());
                List<Provider> providerList;
                if (request.getJsonData() != null) {
                    Provider provider = JSONObject.parseObject(request.getJsonData(), Provider.class);
                    providerList = providerService.getProviderList(provider);
                } else {
                    providerList = providerService.getProviderList();
                }
                sendJsonResponse(outputStream, providerList, request);
            }
            break;

            // 根据ID查询供应商信息
            case "/server/provider/get": {
                System.out.println("根据id查询供应商信息");
                System.out.println(request.getJsonData());
                Provider provider = JSONObject.parseObject(request.getJsonData(), Provider.class);
                Provider one = providerService.getProvider(provider.getId());

                sendJsonResponse(outputStream, one, request);
            }
            break;

            // 根据id删除供应商
            case "/server/provider/delete": {
                System.out.println("根据id删除供应商");
                System.out.println(request.getJsonData());
                Provider provider = JSONObject.parseObject(request.getJsonData(), Provider.class);
                providerService.deleteProvider(provider.getId());
                userService.save();

                sendJsonResponse(outputStream, providerService.getProviderList(), request);
            }
            break;

            // 账单模块
            // 添加或者修改账单
            case "/server/bill/modify": {
                System.out.println("账单添加或修改");
                System.out.println(request.getFormData());
                Bill bill = JSONObject.parseObject(JSONObject.toJSONString(request.getFormData()), Bill.class);
                // 设置时间
                String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date().getTime());
                if (bill != null) {
                    // 根据供应商id设置供应商名称
                    bill.setProviderName(providerService.getProvider(bill.getProviderId()).getName());
                    // id为0 表示新增
                    bill.setUpdateTime(time);
                    if (bill.getId() == 0) {
                        billService.addBill(bill);
                    } else {
                        billService.updateBill(bill);
                    }
                    setRedirect(outputStream, request, "/bill_list.html");
                } else
                    setRedirect(outputStream, request, "/form_post_fail.html");
            }
            break;

            // 账单查询
            case "/server/bill/list": {
                System.out.println("账单查询");
                System.out.println(request.getJsonData());
                List<Bill> billList;
                if (request.getJsonData() != null) {
                    Bill bill = JSONObject.parseObject(request.getJsonData(), Bill.class);
                    billList = billService.getBillList(bill);
                } else {
                    billList = billService.getBillList();
                }
                sendJsonResponse(outputStream, billList, request);
            }
            break;

            // 根据id查询供应商信息
            case "/server/bill/get": {
                System.out.println("根据id查询账单信息");
                System.out.println(request.getJsonData());
                Bill bill = JSONObject.parseObject(request.getJsonData(), Bill.class);
                Bill one = billService.getBill(bill.getId());

                sendJsonResponse(outputStream, one, request);
            }
            break;

            // 账单删除
            case "/server/bill/delete": {
                System.out.println("账单删除");
                System.out.println(request.getJsonData());
                Bill bill = JSONObject.parseObject(request.getJsonData(), Bill.class);
                billService.deleteBill(bill.getId());
                outputStream.write("HTTP/1.1 200 OK\n".getBytes());
                outputStream.write("\n".getBytes());
            }
            break;
            case "/server/user/getInfo": {
                Object loginUser = request.getMbmSession().get("user");
                sendJsonResponse(outputStream, loginUser, request);
            }
            break;
            case "/server/user/quit": {
                // 将服务器缓存的session清除
                MbmSession session = request.getMbmSession();
                SessionUtil.invalidateSession(session);
                // 通知浏览器 cookie中的sessionId失效
                session.invalidate();
                sendOk(outputStream, request);
            }
            break;
        }
    }

    /**
     * 如果用户未登录，抛出异常
     *
     * @param url
     * @param request
     */
    private static void validataAuth(String url, Request request) {
        List<String> whiteList = new ArrayList<>();
        whiteList.add("/server/user/login");
        if (whiteList.contains(url)) {
            return;
        }

        Object user = request.getMbmSession().get("user");
        if (user == null) {
            // 用户未登录
            throw new BadRequestException("用户未登录");
        }
    }

    private static void sendJsonResponse(OutputStream outputStream, Object object, Request request)
            throws IOException {
        String msg = JSONObject.toJSONString(object);

        outputStream.write("HTTP/1.1 200 OK\n".getBytes());
        outputStream.write("Content-Type: application/json; charset=utf-8\n".getBytes());
        outputStream.write(("Content-Length: " + msg.getBytes().length).getBytes());
        outputStream.write("\n".getBytes());

        writeCookie(outputStream, request);

        outputStream.write("\n".getBytes());
        outputStream.write(msg.getBytes());
    }

    private static void setRedirect(OutputStream outputStream, Request request, String s)
            throws IOException {
        outputStream.write("HTTP/1.1 302 Found\n".getBytes());
        outputStream
                .write(("Location: " + "http://" + request.getHost() + s).getBytes());
        outputStream.write("\n".getBytes());

        writeCookie(outputStream, request);

        outputStream.write("\n".getBytes());
    }

    private static void sendOk(OutputStream outputStream, Request request)
            throws IOException {
        outputStream.write("HTTP/1.1 200 OK\n".getBytes());
        writeCookie(outputStream, request);
        outputStream.write("\n".getBytes());
    }

    private static void sendFailure(OutputStream outputStream, String s, Request request) throws IOException {
        outputStream.write("HTTP/1.1 400 Bad Request\n".getBytes());
        outputStream.write("Content-Type: text/html; charset=utf-8\n".getBytes());
        outputStream.write(("Content-Length" + s.getBytes().length + "\n").getBytes());
        writeCookie(outputStream, request);
        outputStream.write("\n".getBytes());
        outputStream.write((s + "\n").getBytes());
    }

    private static void writeCookie(OutputStream outputStream, Request request) throws IOException {
        MbmSession session = request.getMbmSession();
        if (session.isValid()) {
            // 生效
            outputStream.write(("Set-Cookie: SESSIONID=" + session.getSessionId()).getBytes());
        } else {
            // 失效
            // Max-Age通知浏览器，cookie的有效时间，秒为单位。
            outputStream.write(("Set-Cookie: SESSIONID=" + session.getSessionId() + "; Max-Age=0").getBytes());

        }
        // Map<String, String> cookie = request.getCookie();


        outputStream.write(("\n").getBytes());
    }

    private static void writeStaticResource(OutputStream outputStream, String resourcePath , Request request)
            throws IOException {
        BufferedInputStream bufferedInputStream = new BufferedInputStream(
                HttpServerConcurrent.class.getResourceAsStream(resourcePath));
        int available = bufferedInputStream.available();

        outputStream.write("HTTP/1.1 200 OK\n".getBytes());
        // 只有html文件需要增加这句话
        if (resourcePath.endsWith(".html")) {
            outputStream.write("Content-Type: text/html; charset=utf-8\n".getBytes());
        }
        outputStream.write(("Content-Length: " + available + "\n").getBytes());
        writeCookie(outputStream, request);
        outputStream.write("\n".getBytes());

        byte[] buf = new byte[1024];

        int count = bufferedInputStream.read(buf);
        while (count > 0) {
            outputStream.write(buf, 0, count);
            count = bufferedInputStream.read(buf);
        }

        bufferedInputStream.close();
    }
}
